Fast acrobatic maneuvers enable arboreal spiders to hunt dangerous prey
Authors:
Alfonso Aceves-Aparicio*1, 2, Ajay Narendra1, Donald James McLean1, Elizabeth C. Lowe1, Marcelo Christian2, Jonas O. Wolff1, Jutta M. Schneider2 and Marie E. Herberstein1
1, Department of Biological Sciences, Macquarie University, Sydney, NSW, 2109, Australia
2, Institute of Zoology, Universität Hamburg, Hamburg, Germany Corresponding author: Alfonso Aceves-Aparicio Correspondence: bioarach@gmail.com
This is the code used to extract velocity data and generate figures from the attack sequences recorded as high speed video.
library(trajr)
library(tidyverse)
library(readxl)
library(kableExtra)
library(patchwork)
# library(lessR)
Load excel
Excel files contain control data for each video sequence. And manually scored behaviours occurring during the attack strike phase.
ajay_page1 <- read_excel("./Data/velocity_5seq_20200219a.xlsx", col_names = T,
sheet = "velocity_5seq_20200219", range = "A1:AB23")%>%
rename("filename" = "f-name") %>%
mutate(filename = str_replace(filename, ".$", "")) %>%
rename("contact" = Seq3...15) %>%
mutate(firstMoveFrame = frame1 - posFile_start)
# View(ajay_page1)
# current A1:AB23
# alternative range: A1:J23
# ajay_page1 %>% View()
Matching pos files with spreadsheet
# Grab the names of all the files in the working directory as set above
all_pos <- list.files("./Data2", pattern =".pos", full.names = TRUE)
# Grabs the names of the video files from the control spreadsheet
# note the current directory only contains videos from the chronos camera
input_list <- ajay_page1 %>%
select("filename") %>%
pull()
# input_list
# creates a single object to be used as a pattern to grab the pos files that match those in the spreadsheet
pattern <- paste(input_list, sep="", collapse="|")
# list of pos files that match names in the spreadsheets
chosen_pos <- all_pos[grepl(pattern, all_pos)]
Containers
# first containers --------------------------------------------------------
# coord_files <- chosen_pos %>%
# str_subset(pattern = "-(\\d){2}.pos$")
coord_files <- chosen_pos %>%
str_subset(pattern = "(\\d|\\d_fail)\\.pos$")
# scale_files <- chosen_pos %>%
# str_subset(pattern = "_(\\d){2}mm.pos$")
scale_files <- chosen_pos %>%
str_subset(pattern = "(\\d){1,}_scale_(\\d){1,}(mm)|(\\d){1,}_fail_scale_(\\d){1,}(mm)\\.pos$")
# extract the known distances from the scale files
the_scales <- scale_files %>%
as.data.frame() %>%
rename("scaleFiles" = ".") %>%
mutate(scaleValues = str_extract(scaleFiles, pattern = "_(\\d){1,2}mm")) %>%
mutate(scaleValues = str_extract(string = scaleValues, pattern = "_\\d+")) %>%
mutate(scaleValues = str_replace(scaleValues, pattern = "_", replacement = "0.0")) %>%
mutate(scaleValues = as.numeric(scaleValues))
Creating trajectory objects
We used the R package “Trajr” to generate the trajectories (the path of the moving spiders) followed by the spiders during the duration of the attack strike against the ant prey.
Each trajectory was smoothed by applying a Savitzky-Golay to reduce high frequency noise while preserving the shape of the trajectory (function: TrajSmoothSG). Further, we used the TrajDerivatives function to calculate change in speed along a each trajectory. The outcome is stored in a “derivatives” object.
Trajr:
McLean DJ, Skowron Volponi MA. trajr: An R package for characterisation of animal trajectories. Ethology. 2018;00:1–9. https://doi.org/10.1111/eth.12739.
https://cran.rstudio.com/web/packages/trajr/vignettes/trajr-vignette.html
derivs_list <- pmap(list(coord_files, scale_files, the_scales$scaleValues), loadSample_FromList2) %>%
map(TrajSmoothSG, p = 5, n = 23) %>%
map(TrajDerivatives) %>%
set_names(mylabelseq("Derivs_", 1, 22, 1))
derivs_names <- names(derivs_list)
Plots for change in speed along a each trajectory
Excluding trajectory 3
Exploration of the trajectory and speed change of the third high speed video showed an usual pattern. Further revision of the video showed that this was a failed attacked trigger towards an ant at a greater distance. Thus, the ant slayer spider did not attempt to tag the ant prey with silk. For this, the sequence is excluded.
trajs_list <- list(coords = coord_files, scales = scale_files, scaleValues = the_scales)
traj_03 <- loadSample_FromList(listObject = trajs_list, number = 3)
par(mfrow = c(1,2)); derivs_list$Derivs_03 %>% plotSpeed(); plot(traj_03, lwd = 1, lty = 1)

Separating distinct trajectories
The following trajectories do not fit general settings applied to the rest of the trajectories and are thus using particular settings shown below (section “Distinct trajectories”).
removables <- c(2, 3, 12)
derivs_list_short <- derivs_list[- removables]
derivs_names_short <- derivs_names[- removables]
# names(derivs_list_short) <- derivs_names_short
Frame indexes
# The "IndexLimitsManual" function pulls the index position of the following frames:
# last frame where speed is zero (the onset of the ant slayer attack)
# frame where the acrobatic strike reaches its maxumum speed
# default values used for the function
# IndexLimitsManual(derivs_object = derivs_list_sample$Derivs_01, startThreshold = 1e-8, thresholdFrame = 1, limit_range = 155, window_size = 35)
indexes_short <- map(derivs_list_short, IndexLimitsManual)
# names(indexes_short)
Maxima speeds
The following plots show the speed change during the first phase of the attack (acrobatic strike) The blue vertical line marks the onset of the spiders’ attack (the spider begins moving) The red line shows where the peak speed was reached during the acrobatic strike Note this is restricted to the speeds achieved by the spiders while directing its attack to the ant prey and before dropping off from the trunk surface.
pmap(list(derivs_list_short, as.list(names(derivs_list_short)), indexes_short),
~ggplot() + geom_line(aes(x= ..1$speedTimes*1000, y= ..1$speed*100)) +
ggtitle(..2) +
geom_vline(xintercept = ..3$`maxim(um/a)`*4, col = "red")+
geom_vline(xintercept = c(..3$start_index)*4, col = "blue") +
xlab("Time (ms)") +
ylab("Speed (cm/s)") +
theme_bw()
)
## $Derivs_01

##
## $Derivs_04

##
## $Derivs_05

##
## $Derivs_06

##
## $Derivs_07

##
## $Derivs_08

##
## $Derivs_09

##
## $Derivs_10

##
## $Derivs_11

##
## $Derivs_13

##
## $Derivs_14

##
## $Derivs_15

##
## $Derivs_16

##
## $Derivs_17

##
## $Derivs_18

##
## $Derivs_19

##
## $Derivs_20

##
## $Derivs_21

##
## $Derivs_22

Distinct trajectories
Trajectories 02 and 12 were affected by noisy speed curves before the onset of the attack. These were adjusted and corroborated with visual inspection of the videos to make sure that the selected frame was the last one before the attack onset.
# removables <- c(2, 3, 12)
derivs_list_special <- derivs_list[removables]
derivs_names_special <- derivs_names[removables]
names(derivs_list_special) <- derivs_names_special
# str(derivs_list_special)
Derivs 02
# get index frames
indexes_derivs_02 <- IndexLimitsManual(derivs_object = derivs_list_special$Derivs_02, startThreshold = 1e-8, thresholdFrame = 19, limit_range = 155, window_size = 25)
# plot
ggplot() +
geom_line(aes(x = derivs_list_special$Derivs_02$speedTimes*1000, y = derivs_list_special$Derivs_02$speed*100)) +
geom_vline(xintercept = indexes_derivs_02$`maxim(um/a)`[2]*4, col = "red") +
geom_vline(xintercept = c(indexes_derivs_02$start_index, indexes_derivs_02$end_index)*4, col = "blue") +
labs(title = "Derivs_02",
x = "Time (ms)",
y = "Speed (cm/s)") +
theme_minimal()

# indexes_derivs_02$`maxim(um/a)`
# indexes_derivs_02$end_index
Derivs 12
# get index frames
indexes_derivs_12 <- IndexLimitsManual(derivs_object = derivs_list_special$Derivs_12, startThreshold = 1e-8, thresholdFrame = 19, limit_range = 155, window_size = 35)
# plot
ggplot() +
geom_line(aes(x = derivs_list_special$Derivs_12$speedTimes*1000, y = derivs_list_special$Derivs_12$speed*100)) +
geom_vline(xintercept = indexes_derivs_12$`maxim(um/a)`*4, col = "red") +
geom_vline(xintercept = c(indexes_derivs_12$start_index, indexes_derivs_12$end_index)*4, col = "blue") +
labs(title = "Derivs_12",
x = "Time (ms)",
y = "Speed (cm/s)") +
theme_minimal()

# indexes_derivs_02$`maxim(um/a)`
# indexes_derivs_02$end_index
Figure 1 Panel F
The figure plots the speed change from the last frame before the acrobatic attack onset to the maximum speed reached for 17/19 inspected high speed videos. The remaining 2 (02 and 12) are added later.
# loop me up!
# colour palette
cbp1 <- c("#999999", "#E69F00", "#56B4E9", "#009E73",
"#F0E442", "#0072B2", "#D55E00", "#CC79A7")
# to recycle colours
cbp1_24 <- rep(cbp1, 3)
mp <- ggplot()
for(i in seq_along(derivs_list_short)) {
idata <- tibble("speed" = derivs_list_short[[i]]$speed[indexes_short[[i]]$start_index:indexes_short[[i]]$`maxim(um/a)`]) %>%
mutate("index" = seq_along(speed)-1)
mp <- mp + geom_line(data = idata,
aes(x = index*4, y = speed*100), colour = cbp1_24[i]) +
geom_point(data = idata,
aes(x = last(index)*4,
y = last(speed*100)),
colour = cbp1_24[i]) +
expand_limits(x = c(0, 160), y = c(0, 65)) +
ylab("Speed (cm/s)") +
xlab("Time (ms)") +
theme_classic() +
theme(panel.border = element_blank())
}
# the version below does not include speed for trajectories 02 and 12
# print(mp)
# mp +
# scale_y_continuous(expand = expansion(mult = c(0, .1))) +
# scale_x_continuous(expand = expansion(mult = c(0, .1)))
Curves for trajectories 02 and 12 are created with the distinct settings created before to capture the correct frames of importance
# 02
derivs_02_data <- tibble("speed" = derivs_list_special$Derivs_02$speed[indexes_derivs_02$start_index:indexes_derivs_02$`maxim(um/a)`[2]]) %>%
mutate("index" = seq_along(speed)-1)
mp <- mp +
geom_line(data = derivs_02_data,
aes(x = index*4, y = speed*100), colour = cbp1_24[7]) +
geom_point(data = derivs_02_data,
aes(x = last(index)*4,
y = last(speed*100)),
colour = cbp1_24[7]) +
expand_limits(x = c(0, 160), y = c(0, 65)) +
ylab("Speed (cm/s)") +
xlab("Time (ms)") +
theme_bw()
# 12
derivs_12_data <- tibble("speed" = derivs_list_special$Derivs_12$speed[indexes_derivs_12$start_index:indexes_derivs_12$`maxim(um/a)`]) %>%
mutate("index" = seq_along(speed)-1)
mp <- mp +
geom_line(data = derivs_12_data,
aes(x = index*4, y = speed*100), colour = cbp1_24[8]) +
geom_point(data = derivs_12_data,
aes(x = last(index)*4,
y = last(speed*100)),
colour = cbp1_24[8]) +
expand_limits(x = c(0, 160), y = c(0, 65)) +
ylab("Speed (cm/s)") +
xlab("Time (ms)") +
theme_bw()
Plot including speed changes for all trajectories
print(mp)

# mp+theme(panel.border = element_blank())
Speed & duration
Max speeds for each spider and the elapsed time while going from 0 to to max.
results <- map_dfr(derivs_list_short, SpeedAndTime2)
# results %>% kbl() %>%
# kable_styling(full_width = F)
# rename("Max speed (cm/s)" = max_speed,
# "Elapsed time (ms)" = elapsed_time)
res_02 <- SpeedAndTime2(derivatives_list = derivs_list_special$Derivs_02, thresholdFrame = 19, window_size = 25, multiMax = 2)
res_12 <- SpeedAndTime2(derivatives_list = derivs_list_special$Derivs_12, thresholdFrame = 19, window_size = 35)
speeds_times <- bind_rows(results, res_02, res_12) %>%
mutate(camefrom = c(derivs_names_short, "Derivs_02", "Derivs_12"))
speeds_times %>% kbl() %>%
kable_styling(full_width = F)
|
max_speed
|
elapsed_time
|
camefrom
|
|
11.57657
|
116
|
Derivs_01
|
|
29.94638
|
112
|
Derivs_04
|
|
61.83679
|
132
|
Derivs_05
|
|
19.86896
|
128
|
Derivs_06
|
|
11.17088
|
96
|
Derivs_07
|
|
21.52736
|
120
|
Derivs_08
|
|
31.64278
|
104
|
Derivs_09
|
|
33.36874
|
152
|
Derivs_10
|
|
14.53998
|
92
|
Derivs_11
|
|
29.30936
|
100
|
Derivs_13
|
|
29.20735
|
104
|
Derivs_14
|
|
15.24193
|
84
|
Derivs_15
|
|
25.19305
|
108
|
Derivs_16
|
|
33.06568
|
88
|
Derivs_17
|
|
25.37552
|
108
|
Derivs_18
|
|
23.51403
|
104
|
Derivs_19
|
|
30.45109
|
92
|
Derivs_20
|
|
22.21806
|
76
|
Derivs_21
|
|
15.98763
|
108
|
Derivs_22
|
|
24.35238
|
148
|
Derivs_02
|
|
32.73323
|
96
|
Derivs_12
|
speeds_times %>%
summarise(avgSpeed = mean(max_speed), avgTime = mean(elapsed_time))
# the median
table(speeds_times$elapsed_time)
##
## 76 84 88 92 96 100 104 108 112 116 120 128 132 148 152
## 1 1 1 2 2 1 3 3 1 1 1 1 1 1 1
median(speeds_times$elapsed_time)
## [1] 104
inset <- speeds_times %>%
ggplot() +
geom_boxplot(aes(elapsed_time)) +
expand_limits(x = c(0, 160)) +
theme( panel.grid = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
# panel.background = element_blank(),
panel.background = element_rect(fill = "transparent",colour = NA),
plot.background = element_rect(fill = "transparent",colour = NA),
)
inset <- inset +
theme(legend.position = "none",
panel.grid = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
# rect = element_rect(fill = "transparent"),
# panel.background = element_blank(),
)
Panel F in figure 1 including inset box plot for elapsed time during speed change
# mp+geom_vline(xintercept = 104)+geom_vline(xintercept = 152) +
# inset_element (p = inset,
# left = -0.018,
# bottom = 0.80,
# right = 1.012,
# top = 0.95, align_to = "panel")
ggp_combi <- mp + theme_classic() +
inset_element (p = inset,
left = -0.018,
bottom = 0.89,
right = 1.012,
top = 0.99, align_to = "panel")
ggp_combi

# ggsave(filename = "panelF.pdf", plot = ggp_combi, device = "pdf", path = "./gg_plots")
# setwd("/Users/alfonsoaceves/Downloads/Ant Slayer Speed/gg_plots")
# write_csv(speeds_times, "speeds_times.csv")
# title: "R Notebook"
# output:
# html_document:
# code_folding: "show"
# toc: TRUE
# toc_float: TRUE
# df_print: paged
# editor_options:
# chunk_output_type: console
LS0tCnRpdGxlOiAiQW50IFNsYXllciIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgRmFzdCBhY3JvYmF0aWMgbWFuZXV2ZXJzIGVuYWJsZSBhcmJvcmVhbCBzcGlkZXJzIHRvIGh1bnQgZGFuZ2Vyb3VzIHByZXkKCioqQXV0aG9yczoqKgoKQWxmb25zbyBBY2V2ZXMtQXBhcmljaW9cKl4xLMKgMl4sIEFqYXkgTmFyZW5kcmFeMV4sIERvbmFsZCBKYW1lcyBNY0xlYW5eMSxeIEVsaXphYmV0aCBDLiBMb3dlXjFeLCBNYXJjZWxvIENocmlzdGlhbl4yXiwgSm9uYXMgTy4gV29sZmZeMV4sIEp1dHRhIE0uIFNjaG5laWRlcl4yXiBhbmQgTWFyaWUgRS4gSGVyYmVyc3RlaW5eMV4KCjEsIERlcGFydG1lbnQgb2YgQmlvbG9naWNhbCBTY2llbmNlcywgTWFjcXVhcmllIFVuaXZlcnNpdHksIFN5ZG5leSwgTlNXLCAyMTA5LCBBdXN0cmFsaWEKCjIsIEluc3RpdHV0ZSBvZiBab29sb2d5LCBVbml2ZXJzaXTDpHQgSGFtYnVyZywgSGFtYnVyZywgR2VybWFueSBDb3JyZXNwb25kaW5nIGF1dGhvcjogQWxmb25zbyBBY2V2ZXMtQXBhcmljaW8gQ29ycmVzcG9uZGVuY2U6IFtiaW9hcmFjaFxAZ21haWwuY29tXShtYWlsdG86YmlvYXJhY2hAZ21haWwuY29tKXsuZW1haWx9CgpUaGlzIGlzIHRoZSBjb2RlIHVzZWQgdG8gZXh0cmFjdCB2ZWxvY2l0eSBkYXRhIGFuZCBnZW5lcmF0ZSBmaWd1cmVzIGZyb20gdGhlIGF0dGFjayBzZXF1ZW5jZXMgcmVjb3JkZWQgYXMgaGlnaCBzcGVlZCB2aWRlby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodHJhanIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHBhdGNod29yaykKIyBsaWJyYXJ5KGxlc3NSKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmdldHdkKCkKIyBzZXR3ZCgiL1VzZXJzL2FsZm9uc29hY2V2ZXMvRG93bmxvYWRzL0FudCBTbGF5ZXIgU3BlZWQvIikKc291cmNlKCIuL1IvZnVuY3Rpb25zLlIiKQpgYGAKCiMjIExvYWQgZXhjZWwKCkV4Y2VsIGZpbGVzIGNvbnRhaW4gY29udHJvbCBkYXRhIGZvciBlYWNoIHZpZGVvIHNlcXVlbmNlLiBBbmQgbWFudWFsbHkgc2NvcmVkIGJlaGF2aW91cnMgb2NjdXJyaW5nIGR1cmluZyB0aGUgYXR0YWNrIHN0cmlrZSBwaGFzZS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFqYXlfcGFnZTEgPC0gcmVhZF9leGNlbCgiLi9EYXRhL3ZlbG9jaXR5XzVzZXFfMjAyMDAyMTlhLnhsc3giLCBjb2xfbmFtZXMgPSBULCAKc2hlZXQgPSAidmVsb2NpdHlfNXNlcV8yMDIwMDIxOSIsIHJhbmdlID0gIkExOkFCMjMiKSU+JSAKICByZW5hbWUoImZpbGVuYW1lIiA9ICJmLW5hbWUiKSAlPiUgCiAgbXV0YXRlKGZpbGVuYW1lID0gc3RyX3JlcGxhY2UoZmlsZW5hbWUsICIuJCIsICIiKSkgJT4lIAogIHJlbmFtZSgiY29udGFjdCIgPSBTZXEzLi4uMTUpICU+JQogIG11dGF0ZShmaXJzdE1vdmVGcmFtZSA9IGZyYW1lMSAtIHBvc0ZpbGVfc3RhcnQpCiMgVmlldyhhamF5X3BhZ2UxKQojIGN1cnJlbnQgQTE6QUIyMwojIGFsdGVybmF0aXZlIHJhbmdlOiBBMTpKMjMKIyBhamF5X3BhZ2UxICU+JSBWaWV3KCkKCgpgYGAKCiMjIE1hdGNoaW5nIHBvcyBmaWxlcyB3aXRoIHNwcmVhZHNoZWV0CgpgYGB7cn0KIyBHcmFiIHRoZSBuYW1lcyBvZiBhbGwgdGhlIGZpbGVzIGluIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBhcyBzZXQgYWJvdmUKCmFsbF9wb3MgPC0gbGlzdC5maWxlcygiLi9EYXRhMiIsIHBhdHRlcm4gPSIucG9zIiwgZnVsbC5uYW1lcyA9IFRSVUUpCgojIEdyYWJzIHRoZSBuYW1lcyBvZiB0aGUgdmlkZW8gZmlsZXMgZnJvbSB0aGUgY29udHJvbCBzcHJlYWRzaGVldAojIG5vdGUgdGhlIGN1cnJlbnQgZGlyZWN0b3J5IG9ubHkgY29udGFpbnMgdmlkZW9zIGZyb20gdGhlIGNocm9ub3MgY2FtZXJhCmlucHV0X2xpc3QgPC0gYWpheV9wYWdlMSAlPiUgCiAgc2VsZWN0KCJmaWxlbmFtZSIpICU+JSAKICBwdWxsKCkKCiMgaW5wdXRfbGlzdAoKIyBjcmVhdGVzIGEgc2luZ2xlIG9iamVjdCB0byBiZSB1c2VkIGFzIGEgcGF0dGVybiB0byBncmFiIHRoZSBwb3MgZmlsZXMgdGhhdCBtYXRjaCB0aG9zZSBpbiB0aGUgc3ByZWFkc2hlZXQKcGF0dGVybiA8LSBwYXN0ZShpbnB1dF9saXN0LCBzZXA9IiIsIGNvbGxhcHNlPSJ8IikKCiMgbGlzdCBvZiBwb3MgZmlsZXMgdGhhdCBtYXRjaCBuYW1lcyBpbiB0aGUgc3ByZWFkc2hlZXRzCmNob3Nlbl9wb3MgPC0gYWxsX3Bvc1tncmVwbChwYXR0ZXJuLCBhbGxfcG9zKV0KYGBgCgojIyBDb250YWluZXJzCgpgYGB7cn0KIyBmaXJzdCBjb250YWluZXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIGNvb3JkX2ZpbGVzIDwtIGNob3Nlbl9wb3MgJT4lIAogICMgc3RyX3N1YnNldChwYXR0ZXJuID0gIi0oXFxkKXsyfS5wb3MkIikKCmNvb3JkX2ZpbGVzIDwtIGNob3Nlbl9wb3MgJT4lIAogIHN0cl9zdWJzZXQocGF0dGVybiA9ICIoXFxkfFxcZF9mYWlsKVxcLnBvcyQiKQoKIyBzY2FsZV9maWxlcyA8LSBjaG9zZW5fcG9zICU+JSAKICAjIHN0cl9zdWJzZXQocGF0dGVybiA9ICJfKFxcZCl7Mn1tbS5wb3MkIikKCnNjYWxlX2ZpbGVzIDwtIGNob3Nlbl9wb3MgJT4lIAogIHN0cl9zdWJzZXQocGF0dGVybiA9ICIoXFxkKXsxLH1fc2NhbGVfKFxcZCl7MSx9KG1tKXwoXFxkKXsxLH1fZmFpbF9zY2FsZV8oXFxkKXsxLH0obW0pXFwucG9zJCIpCgojIGV4dHJhY3QgdGhlIGtub3duIGRpc3RhbmNlcyBmcm9tIHRoZSBzY2FsZSBmaWxlcwp0aGVfc2NhbGVzIDwtIHNjYWxlX2ZpbGVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJlbmFtZSgic2NhbGVGaWxlcyIgPSAiLiIpICU+JSAKICBtdXRhdGUoc2NhbGVWYWx1ZXMgPSAgc3RyX2V4dHJhY3Qoc2NhbGVGaWxlcywgcGF0dGVybiA9ICJfKFxcZCl7MSwyfW1tIikpICU+JSAKICBtdXRhdGUoc2NhbGVWYWx1ZXMgPSAgc3RyX2V4dHJhY3Qoc3RyaW5nID0gc2NhbGVWYWx1ZXMsIHBhdHRlcm4gPSAiX1xcZCsiKSkgJT4lIAogIG11dGF0ZShzY2FsZVZhbHVlcyA9IHN0cl9yZXBsYWNlKHNjYWxlVmFsdWVzLCBwYXR0ZXJuID0gIl8iLCByZXBsYWNlbWVudCA9ICIwLjAiKSkgJT4lIAogIG11dGF0ZShzY2FsZVZhbHVlcyA9IGFzLm51bWVyaWMoc2NhbGVWYWx1ZXMpKQpgYGAKCiMjIENyZWF0aW5nIHRyYWplY3Rvcnkgb2JqZWN0cwoKV2UgdXNlZCB0aGUgUiBwYWNrYWdlICJUcmFqciIgdG8gZ2VuZXJhdGUgdGhlIHRyYWplY3RvcmllcyAodGhlIHBhdGggb2YgdGhlIG1vdmluZyBzcGlkZXJzKSBmb2xsb3dlZCBieSB0aGUgc3BpZGVycyBkdXJpbmcgdGhlIGR1cmF0aW9uIG9mIHRoZSBhdHRhY2sgc3RyaWtlIGFnYWluc3QgdGhlIGFudCBwcmV5LgoKRWFjaCB0cmFqZWN0b3J5IHdhcyBzbW9vdGhlZCBieSBhcHBseWluZyBhIFNhdml0emt5LUdvbGF5IHRvIHJlZHVjZSBoaWdoIGZyZXF1ZW5jeSBub2lzZSB3aGlsZSBwcmVzZXJ2aW5nIHRoZSBzaGFwZSBvZiB0aGUgdHJhamVjdG9yeSAoZnVuY3Rpb246IFRyYWpTbW9vdGhTRykuIEZ1cnRoZXIsIHdlIHVzZWQgdGhlIFRyYWpEZXJpdmF0aXZlcyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgY2hhbmdlIGluIHNwZWVkIGFsb25nIGEgZWFjaCB0cmFqZWN0b3J5LiBUaGUgb3V0Y29tZSBpcyBzdG9yZWQgaW4gYSAiZGVyaXZhdGl2ZXMiIG9iamVjdC4KClRyYWpyOgoKTWNMZWFuIERKLCBTa293cm9uIFZvbHBvbmkgTUEuIHRyYWpyOiBBbiBSIHBhY2thZ2UgZm9yIGNoYXJhY3RlcmlzYXRpb24gb2YgYW5pbWFsIHRyYWplY3Rvcmllcy4gRXRob2xvZ3kuIDIwMTg7MDA6MS0tOS4gPGh0dHBzOi8vZG9pLm9yZy8xMC4xMTExL2V0aC4xMjczOS4+Cgo8aHR0cHM6Ly9jcmFuLnJzdHVkaW8uY29tL3dlYi9wYWNrYWdlcy90cmFqci92aWduZXR0ZXMvdHJhanItdmlnbmV0dGUuaHRtbD4KCmBgYHtyfQpkZXJpdnNfbGlzdCA8LSBwbWFwKGxpc3QoY29vcmRfZmlsZXMsIHNjYWxlX2ZpbGVzLCB0aGVfc2NhbGVzJHNjYWxlVmFsdWVzKSwgbG9hZFNhbXBsZV9Gcm9tTGlzdDIpICU+JSAKICBtYXAoVHJhalNtb290aFNHLCBwID0gNSwgbiA9IDIzKSAlPiUgCiAgbWFwKFRyYWpEZXJpdmF0aXZlcykgJT4lIAogIHNldF9uYW1lcyhteWxhYmVsc2VxKCJEZXJpdnNfIiwgMSwgMjIsIDEpKQoKZGVyaXZzX25hbWVzIDwtIG5hbWVzKGRlcml2c19saXN0KQpgYGAKCiMjIFBsb3RzIGZvciBjaGFuZ2UgaW4gc3BlZWQgYWxvbmcgYSBlYWNoIHRyYWplY3Rvcnkgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgoKIyMjIENvbXBhY3QgdmlldwpgYGB7cn0KcGFyKG1mcm93ID0gYygzLDIpKTtmb3IoaSBpbiBzZXFfYWxvbmcoZGVyaXZzX25hbWVzKSkgewogIGRlcml2c19saXN0W1tpXV0gJT4lIHBsb3RTcGVlZCgpCiAgdGl0bGUoZGVyaXZzX25hbWVzW2ldKQp9CmBgYAoKIyMjIExhcmdlIHZpZXcKCmBgYHtyfQpmb3IoaSBpbiBzZXFfYWxvbmcoZGVyaXZzX25hbWVzKSkgewogIGRlcml2c19saXN0W1tpXV0gJT4lIHBsb3RTcGVlZCgpCiAgdGl0bGUoZGVyaXZzX25hbWVzW2ldKQp9CmBgYAoKCgojIyBFeGNsdWRpbmcgdHJhamVjdG9yeSAzCgpFeHBsb3JhdGlvbiBvZiB0aGUgdHJhamVjdG9yeSBhbmQgc3BlZWQgY2hhbmdlIG9mIHRoZSB0aGlyZCBoaWdoIHNwZWVkIHZpZGVvIHNob3dlZCBhbiB1c3VhbCBwYXR0ZXJuLiBGdXJ0aGVyIHJldmlzaW9uIG9mIHRoZSB2aWRlbyBzaG93ZWQgdGhhdCB0aGlzIHdhcyBhIGZhaWxlZCBhdHRhY2tlZCB0cmlnZ2VyIHRvd2FyZHMgYW4gYW50IGF0IGEgZ3JlYXRlciBkaXN0YW5jZS4gVGh1cywgdGhlIGFudCBzbGF5ZXIgc3BpZGVyIGRpZCBub3QgYXR0ZW1wdCB0byB0YWcgdGhlIGFudCBwcmV5IHdpdGggc2lsay4gRm9yIHRoaXMsIHRoZSBzZXF1ZW5jZSBpcyBleGNsdWRlZC4KCmBgYHtyfQp0cmFqc19saXN0IDwtIGxpc3QoY29vcmRzID0gY29vcmRfZmlsZXMsIHNjYWxlcyA9IHNjYWxlX2ZpbGVzLCBzY2FsZVZhbHVlcyA9IHRoZV9zY2FsZXMpCnRyYWpfMDMgPC0gbG9hZFNhbXBsZV9Gcm9tTGlzdChsaXN0T2JqZWN0ID0gdHJhanNfbGlzdCwgbnVtYmVyID0gMykKCnBhcihtZnJvdyA9IGMoMSwyKSk7IGRlcml2c19saXN0JERlcml2c18wMyAlPiUgcGxvdFNwZWVkKCk7IHBsb3QodHJhal8wMywgbHdkID0gMSwgbHR5ID0gMSkKYGBgCgojIyBTZXBhcmF0aW5nIGRpc3RpbmN0IHRyYWplY3RvcmllcwoKVGhlIGZvbGxvd2luZyB0cmFqZWN0b3JpZXMgZG8gbm90IGZpdCBnZW5lcmFsIHNldHRpbmdzIGFwcGxpZWQgdG8gdGhlIHJlc3Qgb2YgdGhlIHRyYWplY3RvcmllcyBhbmQgYXJlIHRodXMgdXNpbmcgcGFydGljdWxhciBzZXR0aW5ncyBzaG93biBiZWxvdyAoc2VjdGlvbiAiRGlzdGluY3QgdHJhamVjdG9yaWVzIikuCgpgYGB7cn0KCnJlbW92YWJsZXMgPC0gYygyLCAzLCAxMikKCmRlcml2c19saXN0X3Nob3J0IDwtIGRlcml2c19saXN0Wy0gcmVtb3ZhYmxlc10KZGVyaXZzX25hbWVzX3Nob3J0IDwtIGRlcml2c19uYW1lc1stIHJlbW92YWJsZXNdCiMgbmFtZXMoZGVyaXZzX2xpc3Rfc2hvcnQpIDwtIGRlcml2c19uYW1lc19zaG9ydAoKYGBgCgojIyBGcmFtZSBpbmRleGVzCgpgYGB7cn0KIyBUaGUgIkluZGV4TGltaXRzTWFudWFsIiBmdW5jdGlvbiBwdWxscyB0aGUgaW5kZXggcG9zaXRpb24gb2YgdGhlIGZvbGxvd2luZyBmcmFtZXM6CiMgbGFzdCBmcmFtZSB3aGVyZSBzcGVlZCBpcyB6ZXJvICh0aGUgb25zZXQgb2YgdGhlIGFudCBzbGF5ZXIgYXR0YWNrKQojIGZyYW1lIHdoZXJlIHRoZSBhY3JvYmF0aWMgc3RyaWtlIHJlYWNoZXMgaXRzIG1heHVtdW0gc3BlZWQKCiMgZGVmYXVsdCB2YWx1ZXMgdXNlZCBmb3IgdGhlIGZ1bmN0aW9uCiMgSW5kZXhMaW1pdHNNYW51YWwoZGVyaXZzX29iamVjdCA9IGRlcml2c19saXN0X3NhbXBsZSREZXJpdnNfMDEsIHN0YXJ0VGhyZXNob2xkID0gMWUtOCwgdGhyZXNob2xkRnJhbWUgPSAxLCBsaW1pdF9yYW5nZSA9IDE1NSwgd2luZG93X3NpemUgPSAzNSkKCmluZGV4ZXNfc2hvcnQgPC0gbWFwKGRlcml2c19saXN0X3Nob3J0LCBJbmRleExpbWl0c01hbnVhbCkKIyBuYW1lcyhpbmRleGVzX3Nob3J0KQpgYGAKCiMjIE1heGltYSBzcGVlZHMKClRoZSBmb2xsb3dpbmcgcGxvdHMgc2hvdyB0aGUgc3BlZWQgY2hhbmdlIGR1cmluZyB0aGUgZmlyc3QgcGhhc2Ugb2YgdGhlIGF0dGFjayAoYWNyb2JhdGljIHN0cmlrZSkgVGhlIGJsdWUgdmVydGljYWwgbGluZSBtYXJrcyB0aGUgb25zZXQgb2YgdGhlIHNwaWRlcnMnIGF0dGFjayAodGhlIHNwaWRlciBiZWdpbnMgbW92aW5nKSBUaGUgcmVkIGxpbmUgc2hvd3Mgd2hlcmUgdGhlIHBlYWsgc3BlZWQgd2FzIHJlYWNoZWQgZHVyaW5nIHRoZSBhY3JvYmF0aWMgc3RyaWtlIE5vdGUgdGhpcyBpcyByZXN0cmljdGVkIHRvIHRoZSBzcGVlZHMgYWNoaWV2ZWQgYnkgdGhlIHNwaWRlcnMgKip3aGlsZSoqIGRpcmVjdGluZyBpdHMgYXR0YWNrIHRvIHRoZSBhbnQgcHJleSBhbmQgKipiZWZvcmUqKiBkcm9wcGluZyBvZmYgZnJvbSB0aGUgdHJ1bmsgc3VyZmFjZS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CnBtYXAobGlzdChkZXJpdnNfbGlzdF9zaG9ydCwgYXMubGlzdChuYW1lcyhkZXJpdnNfbGlzdF9zaG9ydCkpLCBpbmRleGVzX3Nob3J0KSwgCiAgICAgfmdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PSAuLjEkc3BlZWRUaW1lcyoxMDAwLCB5PSAuLjEkc3BlZWQqMTAwKSkgKwogICAgICAgZ2d0aXRsZSguLjIpICsKICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC4uMyRgbWF4aW0odW0vYSlgKjQsIGNvbCA9ICJyZWQiKSsKICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLi4zJHN0YXJ0X2luZGV4KSo0LCBjb2wgPSAiYmx1ZSIpICsgCiAgICAgICB4bGFiKCJUaW1lIChtcykiKSArCiAgICAgICB5bGFiKCJTcGVlZCAoY20vcykiKSArCiAgICAgICB0aGVtZV9idygpCikKYGBgCgojIyBEaXN0aW5jdCB0cmFqZWN0b3JpZXMKClRyYWplY3RvcmllcyAwMiBhbmQgMTIgd2VyZSBhZmZlY3RlZCBieSBub2lzeSBzcGVlZCBjdXJ2ZXMgYmVmb3JlIHRoZSBvbnNldCBvZiB0aGUgYXR0YWNrLiBUaGVzZSB3ZXJlIGFkanVzdGVkIGFuZCBjb3Jyb2JvcmF0ZWQgd2l0aCB2aXN1YWwgaW5zcGVjdGlvbiBvZiB0aGUgdmlkZW9zIHRvIG1ha2Ugc3VyZSB0aGF0IHRoZSBzZWxlY3RlZCBmcmFtZSB3YXMgdGhlIGxhc3Qgb25lIGJlZm9yZSB0aGUgYXR0YWNrIG9uc2V0LgoKYGBge3J9CiMgcmVtb3ZhYmxlcyA8LSBjKDIsIDMsIDEyKQoKZGVyaXZzX2xpc3Rfc3BlY2lhbCA8LSBkZXJpdnNfbGlzdFtyZW1vdmFibGVzXQpkZXJpdnNfbmFtZXNfc3BlY2lhbCA8LSBkZXJpdnNfbmFtZXNbcmVtb3ZhYmxlc10KbmFtZXMoZGVyaXZzX2xpc3Rfc3BlY2lhbCkgPC0gZGVyaXZzX25hbWVzX3NwZWNpYWwKIyBzdHIoZGVyaXZzX2xpc3Rfc3BlY2lhbCkKCmBgYAoKRGVyaXZzIDAyCgpgYGB7cn0KIyBnZXQgaW5kZXggZnJhbWVzCmluZGV4ZXNfZGVyaXZzXzAyIDwtIEluZGV4TGltaXRzTWFudWFsKGRlcml2c19vYmplY3QgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18wMiwgc3RhcnRUaHJlc2hvbGQgPSAxZS04LCB0aHJlc2hvbGRGcmFtZSA9IDE5LCBsaW1pdF9yYW5nZSA9IDE1NSwgd2luZG93X3NpemUgPSAyNSkKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18wMiRzcGVlZFRpbWVzKjEwMDAsIHkgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18wMiRzcGVlZCoxMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gaW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYFsyXSo0LCBjb2wgPSAicmVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoaW5kZXhlc19kZXJpdnNfMDIkc3RhcnRfaW5kZXgsIGluZGV4ZXNfZGVyaXZzXzAyJGVuZF9pbmRleCkqNCwgY29sID0gImJsdWUiKSArIAogIGxhYnModGl0bGUgPSAiRGVyaXZzXzAyIiwgCiAgICAgICB4ID0gIlRpbWUgKG1zKSIsCiAgICAgICB5ID0gIlNwZWVkIChjbS9zKSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgaW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYAojIGluZGV4ZXNfZGVyaXZzXzAyJGVuZF9pbmRleAoKYGBgCgpEZXJpdnMgMTIKCmBgYHtyfQojIGdldCBpbmRleCBmcmFtZXMKaW5kZXhlc19kZXJpdnNfMTIgPC0gSW5kZXhMaW1pdHNNYW51YWwoZGVyaXZzX29iamVjdCA9IGRlcml2c19saXN0X3NwZWNpYWwkRGVyaXZzXzEyLCBzdGFydFRocmVzaG9sZCA9IDFlLTgsIHRocmVzaG9sZEZyYW1lID0gMTksIGxpbWl0X3JhbmdlID0gMTU1LCB3aW5kb3dfc2l6ZSA9IDM1KQoKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiRzcGVlZFRpbWVzKjEwMDAsIHkgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiRzcGVlZCoxMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gaW5kZXhlc19kZXJpdnNfMTIkYG1heGltKHVtL2EpYCo0LCBjb2wgPSAicmVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoaW5kZXhlc19kZXJpdnNfMTIkc3RhcnRfaW5kZXgsIGluZGV4ZXNfZGVyaXZzXzEyJGVuZF9pbmRleCkqNCwgY29sID0gImJsdWUiKSArIAogIGxhYnModGl0bGUgPSAiRGVyaXZzXzEyIiwgCiAgICAgICB4ID0gIlRpbWUgKG1zKSIsCiAgICAgICB5ID0gIlNwZWVkIChjbS9zKSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgaW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYAojIGluZGV4ZXNfZGVyaXZzXzAyJGVuZF9pbmRleAoKYGBgCgojIyBGaWd1cmUgMSBQYW5lbCBGCgpUaGUgZmlndXJlIHBsb3RzIHRoZSBzcGVlZCBjaGFuZ2UgZnJvbSB0aGUgbGFzdCBmcmFtZSBiZWZvcmUgdGhlIGFjcm9iYXRpYyBhdHRhY2sgb25zZXQgdG8gdGhlIG1heGltdW0gc3BlZWQgcmVhY2hlZCBmb3IgMTcvMTkgaW5zcGVjdGVkIGhpZ2ggc3BlZWQgdmlkZW9zLiBUaGUgcmVtYWluaW5nIDIgKDAyIGFuZCAxMikgYXJlIGFkZGVkIGxhdGVyLgoKYGBge3J9CgojIGxvb3AgbWUgdXAhCiMgY29sb3VyIHBhbGV0dGUKY2JwMSA8LSBjKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwKICAgICAgICAgICIjRjBFNDQyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikKIyB0byByZWN5Y2xlIGNvbG91cnMKY2JwMV8yNCA8LSByZXAoY2JwMSwgMykKCm1wIDwtIGdncGxvdCgpCmZvcihpIGluIHNlcV9hbG9uZyhkZXJpdnNfbGlzdF9zaG9ydCkpIHsKICAKICBpZGF0YSA8LSB0aWJibGUoInNwZWVkIiA9IGRlcml2c19saXN0X3Nob3J0W1tpXV0kc3BlZWRbaW5kZXhlc19zaG9ydFtbaV1dJHN0YXJ0X2luZGV4OmluZGV4ZXNfc2hvcnRbW2ldXSRgbWF4aW0odW0vYSlgXSkgJT4lIAogICAgbXV0YXRlKCJpbmRleCIgPSBzZXFfYWxvbmcoc3BlZWQpLTEpCiAgCiAgbXAgPC0gbXAgKyBnZW9tX2xpbmUoZGF0YSA9IGlkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGluZGV4KjQsIHkgPSBzcGVlZCoxMDApLCBjb2xvdXIgPSBjYnAxXzI0W2ldKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBpZGF0YSwKICAgICAgICAgICAgICAgYWVzKHggPSBsYXN0KGluZGV4KSo0LCAKICAgICAgICAgICAgICAgICAgIHkgPSAgbGFzdChzcGVlZCoxMDApKSwgCiAgICAgICAgICAgICAgIGNvbG91ciA9IGNicDFfMjRbaV0pICsKICAgIGV4cGFuZF9saW1pdHMoeCA9IGMoMCwgMTYwKSwgeSA9IGMoMCwgNjUpKSArCiAgICB5bGFiKCJTcGVlZCAoY20vcykiKSArCiAgICB4bGFiKCJUaW1lIChtcykiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQp9CgojIHRoZSB2ZXJzaW9uIGJlbG93IGRvZXMgbm90IGluY2x1ZGUgc3BlZWQgZm9yIHRyYWplY3RvcmllcyAwMiBhbmQgMTIKIyBwcmludChtcCkKCgojIG1wICsgCiMgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIC4xKSkpICsKIyAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjEpKSkKCmBgYAoKQ3VydmVzIGZvciB0cmFqZWN0b3JpZXMgMDIgYW5kIDEyIGFyZSBjcmVhdGVkIHdpdGggdGhlIGRpc3RpbmN0IHNldHRpbmdzIGNyZWF0ZWQgYmVmb3JlIHRvIGNhcHR1cmUgdGhlIGNvcnJlY3QgZnJhbWVzIG9mIGltcG9ydGFuY2UKCmBgYHtyfQojIDAyCmRlcml2c18wMl9kYXRhIDwtIHRpYmJsZSgic3BlZWQiID0gZGVyaXZzX2xpc3Rfc3BlY2lhbCREZXJpdnNfMDIkc3BlZWRbaW5kZXhlc19kZXJpdnNfMDIkc3RhcnRfaW5kZXg6aW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYFsyXV0pICU+JSAKICBtdXRhdGUoImluZGV4IiA9IHNlcV9hbG9uZyhzcGVlZCktMSkKCm1wIDwtIG1wICArCmdlb21fbGluZShkYXRhID0gZGVyaXZzXzAyX2RhdGEsIAogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGluZGV4KjQsIHkgPSBzcGVlZCoxMDApLCBjb2xvdXIgPSBjYnAxXzI0WzddKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGVyaXZzXzAyX2RhdGEsCiAgICAgICAgICAgICBhZXMoeCA9IGxhc3QoaW5kZXgpKjQsIAogICAgICAgICAgICAgICAgIHkgPSAgbGFzdChzcGVlZCoxMDApKSwgCiAgICAgICAgICAgICBjb2xvdXIgPSBjYnAxXzI0WzddKSArCiAgZXhwYW5kX2xpbWl0cyh4ID0gYygwLCAxNjApLCB5ID0gYygwLCA2NSkpICsKICB5bGFiKCJTcGVlZCAoY20vcykiKSArCiAgeGxhYigiVGltZSAobXMpIikgKwogIHRoZW1lX2J3KCkKCiMgMTIKZGVyaXZzXzEyX2RhdGEgPC0gdGliYmxlKCJzcGVlZCIgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiRzcGVlZFtpbmRleGVzX2Rlcml2c18xMiRzdGFydF9pbmRleDppbmRleGVzX2Rlcml2c18xMiRgbWF4aW0odW0vYSlgXSkgJT4lIAogIG11dGF0ZSgiaW5kZXgiID0gc2VxX2Fsb25nKHNwZWVkKS0xKQoKbXAgPC0gbXAgICsKZ2VvbV9saW5lKGRhdGEgPSBkZXJpdnNfMTJfZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gaW5kZXgqNCwgeSA9IHNwZWVkKjEwMCksIGNvbG91ciA9IGNicDFfMjRbOF0pICsKICBnZW9tX3BvaW50KGRhdGEgPSBkZXJpdnNfMTJfZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gbGFzdChpbmRleCkqNCwgCiAgICAgICAgICAgICAgICAgeSA9ICBsYXN0KHNwZWVkKjEwMCkpLCAKICAgICAgICAgICAgIGNvbG91ciA9IGNicDFfMjRbOF0pICsKICBleHBhbmRfbGltaXRzKHggPSBjKDAsIDE2MCksIHkgPSBjKDAsIDY1KSkgKwogIHlsYWIoIlNwZWVkIChjbS9zKSIpICsKICB4bGFiKCJUaW1lIChtcykiKSArCiAgdGhlbWVfYncoKQoKYGBgCgpQbG90IGluY2x1ZGluZyBzcGVlZCBjaGFuZ2VzIGZvciBhbGwgdHJhamVjdG9yaWVzCgpgYGB7cn0KcHJpbnQobXApCiMgbXArdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIFNwZWVkICYgZHVyYXRpb24KCk1heCBzcGVlZHMgZm9yIGVhY2ggc3BpZGVyIGFuZCB0aGUgZWxhcHNlZCB0aW1lIHdoaWxlIGdvaW5nIGZyb20gMCB0byB0byBtYXguCgpgYGB7cn0KcmVzdWx0cyA8LSBtYXBfZGZyKGRlcml2c19saXN0X3Nob3J0LCBTcGVlZEFuZFRpbWUyKQojIHJlc3VsdHMgJT4lIGtibCgpICU+JSAKIyAgIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpCgojIHJlbmFtZSgiTWF4IHNwZWVkIChjbS9zKSIgPSBtYXhfc3BlZWQsIAojICAgICAgICAiRWxhcHNlZCB0aW1lIChtcykiID0gZWxhcHNlZF90aW1lKQpgYGAKCmBgYHtyfQpyZXNfMDIgPC0gU3BlZWRBbmRUaW1lMihkZXJpdmF0aXZlc19saXN0ID0gZGVyaXZzX2xpc3Rfc3BlY2lhbCREZXJpdnNfMDIsIHRocmVzaG9sZEZyYW1lID0gMTksIHdpbmRvd19zaXplID0gMjUsIG11bHRpTWF4ID0gMikKCnJlc18xMiA8LSBTcGVlZEFuZFRpbWUyKGRlcml2YXRpdmVzX2xpc3QgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiwgdGhyZXNob2xkRnJhbWUgPSAxOSwgd2luZG93X3NpemUgPSAzNSkKYGBgCgpgYGB7cn0Kc3BlZWRzX3RpbWVzIDwtIGJpbmRfcm93cyhyZXN1bHRzLCByZXNfMDIsIHJlc18xMikgJT4lIAogIG11dGF0ZShjYW1lZnJvbSA9IGMoZGVyaXZzX25hbWVzX3Nob3J0LCAiRGVyaXZzXzAyIiwgIkRlcml2c18xMiIpKSAKCnNwZWVkc190aW1lcyAlPiUga2JsKCkgJT4lIAogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpCgpzcGVlZHNfdGltZXMgJT4lIAogIHN1bW1hcmlzZShhdmdTcGVlZCA9IG1lYW4obWF4X3NwZWVkKSwgYXZnVGltZSA9IG1lYW4oZWxhcHNlZF90aW1lKSkKCiMgdGhlIG1lZGlhbgp0YWJsZShzcGVlZHNfdGltZXMkZWxhcHNlZF90aW1lKQptZWRpYW4oc3BlZWRzX3RpbWVzJGVsYXBzZWRfdGltZSkgCgppbnNldCA8LSBzcGVlZHNfdGltZXMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoZWxhcHNlZF90aW1lKSkgKwogIGV4cGFuZF9saW1pdHMoeCA9IGMoMCwgMTYwKSkgKwogIHRoZW1lKCBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICMgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSksCiAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSksCikKICAKaW5zZXQgPC0gaW5zZXQgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgICAgICAjIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgKQoKYGBgCgpQYW5lbCBGIGluIGZpZ3VyZSAxIGluY2x1ZGluZyBpbnNldCBib3ggcGxvdCBmb3IgZWxhcHNlZCB0aW1lIGR1cmluZyBzcGVlZCBjaGFuZ2UKCmBgYHtyfQoKIyBtcCtnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMDQpK2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDE1MikgKwojIGluc2V0X2VsZW1lbnQgKHAgPSBpbnNldCwKIyBsZWZ0ID0gLTAuMDE4LAojIGJvdHRvbSA9IDAuODAsCiMgcmlnaHQgPSAxLjAxMiwKIyB0b3AgPSAwLjk1LCBhbGlnbl90byA9ICJwYW5lbCIpCgpnZ3BfY29tYmkgPC0gbXAgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBpbnNldF9lbGVtZW50IChwID0gaW5zZXQsCiAgICAgICAgICAgICAgICAgbGVmdCA9IC0wLjAxOCwKICAgICAgICAgICAgICAgICBib3R0b20gPSAwLjg5LAogICAgICAgICAgICAgICAgIHJpZ2h0ID0gMS4wMTIsCiAgICAgICAgICAgICAgICAgdG9wID0gMC45OSwgYWxpZ25fdG8gPSAicGFuZWwiKQpnZ3BfY29tYmkKCiMgZ2dzYXZlKGZpbGVuYW1lID0gInBhbmVsRi5wZGYiLCBwbG90ID0gZ2dwX2NvbWJpLCBkZXZpY2UgPSAicGRmIiwgcGF0aCA9ICIuL2dnX3Bsb3RzIikKYGBgCgpgYGB7cn0KIyBzZXR3ZCgiL1VzZXJzL2FsZm9uc29hY2V2ZXMvRG93bmxvYWRzL0FudCBTbGF5ZXIgU3BlZWQvZ2dfcGxvdHMiKQojIHdyaXRlX2NzdihzcGVlZHNfdGltZXMsICJzcGVlZHNfdGltZXMuY3N2IikKYGBgCgpgYGB7cn0KIyB0aXRsZTogIlIgTm90ZWJvb2siCiMgb3V0cHV0OgojICAgaHRtbF9kb2N1bWVudDoKIyAgICAgY29kZV9mb2xkaW5nOiAic2hvdyIKIyAgICAgdG9jOiBUUlVFCiMgICAgIHRvY19mbG9hdDogVFJVRQojICAgICBkZl9wcmludDogcGFnZWQKIyBlZGl0b3Jfb3B0aW9uczoKIyAgIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCgpgYGAKCgo8YnI+CgoKOjo6IHsudG9jaWZ5LWV4dGVuZC1wYWdlIGRhdGEtdW5pcXVlPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIHN0eWxlPSJoZWlnaHQ6IDA7In0KOjo6Cg==